home *** CD-ROM | disk | FTP | other *** search
/ MacTech 1 to 12 / MacTech-vol-1-12.toast / Tools / HexEdit 1.0.7 ƒ / HexEditSource / Source / EditWindow.c < prev    next >
Text File  |  1994-09-25  |  51KB  |  1,869 lines

  1. /*********************************************************************
  2.  * EditWindow.c
  3.  *
  4.  * HexEdit, a simple hex editor
  5.  * copyright 1993, Jim Bumgardner
  6.  *********************************************************************/
  7. #include "HexEdit.h"
  8. #include "Folders.h"
  9. #include <stdio.h>
  10.  
  11. // Create a new main window using a 'WIND' template from the resource fork
  12. //
  13.  
  14. Boolean         gCursorFlag;
  15. Rect            gCursRect;
  16. Preferences        gPrefs = {AM_Lo, false, true};
  17. short            gForkMode=FM_Smart,gHighChar='~',gOverwrite;
  18. THPrint            gHPrint;
  19. static char        gBuffer[80];
  20. Cursor            gWatchCursor,gIBeamCursor;
  21. short            gMaxHeight=342;
  22.  
  23. void LoadPreferences(void)
  24. {
  25.     Handle    h;
  26.     h = GetResource(PrefResType, PrefResID);
  27.     if (h == NULL || ResError())
  28.         return;
  29.     BlockMove(*h, &gPrefs, sizeof(Preferences));
  30.     ReleaseResource(h);
  31.     if (gPrefs.asciiMode)
  32.         gHighChar = 255;
  33.     else
  34.         gHighChar = '~';
  35. }
  36.  
  37. void SavePreferences(void)
  38. {
  39.     Handle    h;
  40.     while ((h = GetResource(PrefResType, PrefResID)) != NULL) {
  41.         RmveResource(h);
  42.         DisposHandle(h);
  43.     }
  44.     h = NewHandle(sizeof(Preferences));
  45.     if (h == NULL) {
  46.         ErrorAlert(ES_Caution,"Not enough memory");
  47.     }
  48.     else {
  49.         BlockMove(&gPrefs, *h, sizeof(Preferences));
  50.         AddResource(h,PrefResType,PrefResID,"\pPreferences");
  51.         WriteResource(h);
  52.         ReleaseResource(h);
  53.     }
  54. }
  55.  
  56. void InitializeEditor()
  57. {
  58.     OSErr                oe;
  59.     CursHandle            cH = NULL;
  60.  
  61.     if (ScrapInfo.scrapState < 0)
  62.         ZeroScrap();
  63.  
  64.     // Start Profiling
  65. #if PROFILE            // 6/15 Optional profiling support
  66.     freopen("profile.log","w",stdout);        // If console isn't wanted
  67.     InitProfile(200,200);
  68.     _profile = 0;
  69.     // cecho2file("profile.log",false,stdout);    // If console is wanted
  70. #endif
  71.     gMaxHeight = screenBits.bounds.bottom - screenBits.bounds.top;
  72.     if (gMaxHeight < 342)
  73.         gMaxHeight = 342;
  74.  
  75.     cH = GetCursor(watchCursor);
  76.     if (cH)
  77.         gWatchCursor = **cH;
  78.     cH = GetCursor(iBeamCursor);
  79.     if (cH)
  80.         gIBeamCursor = **cH;
  81.  
  82.     PrOpen();
  83.     gHPrint = (THPrint) NewHandle(sizeof(TPrint));
  84.     if (gHPrint == NULL) {
  85.         ErrorAlert(ES_Stop,"Not enough memory");
  86.     }
  87.     PrintDefault(gHPrint);
  88.     PrClose();
  89.  
  90.     LoadPreferences();
  91. }
  92.  
  93. void CleanupEditor()
  94. {
  95.     SavePreferences();
  96. }
  97.  
  98. void NewEditWindow(void)
  99. {
  100.     WindowPtr            theWindow;
  101.     EditWindowPtr        dWin;
  102.     OSErr                oe;
  103.     short                refNum=0;
  104.     Point                where={-1,-1};
  105.     HParamBlockRec        pb;
  106.     FSSpec                workSpec;
  107.     Rect                r,offRect;
  108.  
  109.     // Get the Template & Create the Window, it is set up in the resource fork
  110.     // to not be initially visible 
  111.  
  112.     dWin = (EditWindowPtr) NewPtrClear(sizeof(EditWindowRecord));
  113.     if (dWin == NULL) {
  114.         FSClose(refNum);
  115.         ErrorAlert(ES_Caution, "Can't allocate new window");
  116.         return;
  117.     }
  118.  
  119.     dWin->fork = FT_Data;
  120.     dWin->fileSize = 0L;
  121.     dWin->refNum = 0;
  122.  
  123.     // Initialize WorkSpec
  124.     workSpec = dWin->workSpec;
  125.     oe = FindFolder(-1, kTemporaryFolderType, kCreateFolder, 
  126.                     &workSpec.vRefNum,
  127.                     &workSpec.parID);
  128.     if (oe != noErr) {
  129.         OSErrorAlert(ES_Caution, "FindFolder", oe);
  130.         return;
  131.     }
  132.     BlockMove("\pUntitledw", workSpec.name, 10);
  133.     InsureNameIsUnique(&workSpec);
  134.     HCreate(workSpec.vRefNum,workSpec.parID,workSpec.name,CREATOR, '????');
  135.     if (oe != noErr) {
  136.         OSErrorAlert(ES_Caution, "HCreate", oe);
  137.         return;
  138.     }
  139.     oe = HOpen(workSpec.vRefNum,workSpec.parID,workSpec.name,fsRdWrPerm,&refNum);
  140.     if (oe != noErr) {
  141.         OSErrorAlert(ES_Caution, "HOpen", oe);
  142.         return;
  143.     }
  144.  
  145.     dWin->workSpec = workSpec;
  146.     dWin->workRefNum = refNum;
  147.     dWin->workBytesWritten = 0L;
  148.  
  149.     dWin->fileType = DEFFILETYPE;
  150.     dWin->creator = CREATOR;
  151.     dWin->creationDate = 0L;
  152.  
  153.     theWindow = InitObjectWindow(MainWIND, (ObjectWindowPtr) dWin,false);
  154.     if (theWindow == NULL)
  155.         ErrorAlert(ES_Stop,"Not enough memory");
  156.  
  157.     SizeWindow(theWindow,484+SBarSize-1-1,gMaxHeight-64,true);
  158.     SetRect(&r, 0, 0, MaxWindowWidth+SBarSize-1, gMaxHeight - 44);
  159.     OffsetRect(&r,3,41);
  160.     ((WStateData *)*((WindowPeek) theWindow)->dataHandle)->stdState = r;
  161.  
  162.     SetWTitle(theWindow, "\pUntitled");
  163.  
  164.     ((ObjectWindowPtr) theWindow)->Draw = MyDraw;
  165.     ((ObjectWindowPtr) theWindow)->Idle = MyIdle;
  166.     ((ObjectWindowPtr) theWindow)->HandleClick = MyHandleClick;
  167.     ((ObjectWindowPtr) theWindow)->Dispose = DisposeEditWindow;
  168.     ((ObjectWindowPtr) theWindow)->ProcessKey = MyProcessKey;
  169.     ((ObjectWindowPtr) theWindow)->Save = SaveContents;
  170.     ((ObjectWindowPtr) theWindow)->SaveAs = SaveAsContents;
  171.     ((ObjectWindowPtr) theWindow)->Revert = RevertContents;
  172.     ((ObjectWindowPtr) theWindow)->Activate = MyActivate;
  173.  
  174.     SetRect(&offRect,0,0,MaxWindowWidth,gMaxHeight);
  175.  
  176.     dWin->bitMap.rowBytes = (((MaxWindowWidth-1)/32)+1)*4;
  177.     dWin->bitMap.baseAddr = NewPtrClear( (long) dWin->bitMap.rowBytes * gMaxHeight );
  178.     if (dWin->bitMap.baseAddr == NULL)
  179.         ErrorAlert(ES_Stop,"Not enough memory");
  180.     dWin->bitMap.bounds = offRect;
  181.     
  182.     // Show the window
  183.     ShowWindow(theWindow);
  184.  
  185.     // Make it the current grafport
  186.     SetPort(theWindow);
  187.  
  188.     
  189.     dWin->linesPerPage = ((theWindow->portRect.bottom - SBarSize) - TopMargin - BotMargin - HeaderHeight)/LineHeight;
  190.     dWin->startSel = dWin->endSel = 0L;
  191.     dWin->editMode = EM_Hex;
  192.  
  193.     SetupScrollBars(dWin);
  194.  
  195.     dWin->firstChunk = NewChunk(0L,0L,0L, CT_Unwritten);
  196.     dWin->curChunk = dWin->firstChunk;
  197. }
  198.  
  199. #define DataItem        11
  200. #define RsrcItem        12
  201. #define SmartItem        13
  202.  
  203. /*SFReply        *gReplyPtr;*/
  204.  
  205. pascal int SourceDLOGHook(short item, DialogPtr theDialog)
  206. {
  207.     switch (item) {
  208.     case DataItem:
  209.     case RsrcItem:
  210.     case SmartItem:
  211.         SetControl(theDialog,gForkMode+DataItem,false);
  212.         gForkMode = item - DataItem;
  213.         SetControl(theDialog,gForkMode+DataItem,true);
  214.         return sfHookNullEvent;    /* Redraw the List */
  215.     case sfHookFirstCall:
  216.         SetControl(theDialog,gForkMode+DataItem,true);
  217.         return sfHookNullEvent;
  218. /*    case sfHookNullEvent:*/
  219. /*        {*/
  220. /*            Point    p;*/
  221. /*            short    t;*/
  222. /*            Handle    h;*/
  223. /*            Rect    r;*/
  224. /*            GetMouse(&p);*/
  225. /*            GetDItem(theDialog,DataItem,&t,&h,&r);            */
  226. /*            if (PtInRect(p,&r))*/
  227. /*                DebugStr("\pBoing!");*/
  228. /*        }*/
  229. /*        break;*/
  230.     }
  231.     return item;
  232. }
  233.  
  234. void AskEditWindow(void)
  235. {
  236.     SFReply                macSFReply;
  237.     FSSpec                fSpec;
  238.     long                procID;
  239.     Point                where = {-1,-1};
  240.  
  241.     // StandardGetFile(NULL, -1, NULL, &reply);
  242.     if (!gSys7Flag) {
  243.         where.h = 20;
  244.         where.v = 90;
  245.     }
  246.  
  247.     SFPGetFile(where, "\pFile to Open:", NULL, -1, NULL, (ProcPtr) SourceDLOGHook, 
  248.                 &macSFReply, GetFileDLOG, NULL);
  249.  
  250.     if (macSFReply.good) {
  251.         BlockMove(macSFReply.fName,fSpec.name,macSFReply.fName[0]+1);
  252.         GetWDInfo(macSFReply.vRefNum, &fSpec.vRefNum, &fSpec.parID, &procID);
  253.         OpenEditWindow(&fSpec);
  254.     }
  255.     MyAdjustMenus();
  256. }
  257.  
  258.  
  259.  
  260.  
  261. void OpenEditWindow(FSSpec *fsSpec)
  262. {
  263.     WindowPtr            theWindow;
  264.     EditWindowPtr        dWin;
  265.     OSErr                oe;
  266.     short                refNum=0;
  267.     Point                where={-1,-1};
  268.     HParamBlockRec        pb;
  269.     FSSpec                workSpec;
  270.     Rect                r,offRect;
  271.  
  272.     // Get the Template & Create the Window, it is set up in the resource fork
  273.     // to not be initially visible 
  274.  
  275.  
  276.     pb.fileParam.ioCompletion = 0l;
  277.     pb.fileParam.ioNamePtr = fsSpec->name;
  278.     pb.fileParam.ioVRefNum = fsSpec->vRefNum;
  279.     pb.fileParam.ioDirID = fsSpec->parID;
  280.     pb.fileParam.ioFDirIndex = 0;
  281.  
  282.     if ((oe = PBHGetFInfo(&pb,FALSE)) != noErr) {
  283.         OSErrorAlert(ES_Caution, "PBHGetFInfo", oe);
  284.         return;
  285.     }
  286.  
  287.     // fileSize = pb.fileParam.ioFlLgLen;    // Data Fork Length!!!!
  288.     // GetEOF(refNum,&fileSize);
  289.  
  290.     dWin = (EditWindowPtr) NewPtrClear(sizeof(EditWindowRecord));
  291.     if (dWin == NULL) {
  292.         FSClose(refNum);
  293.         ErrorAlert(ES_Caution, "Can't allocate new window");
  294.         return;
  295.     }
  296.  
  297.     if (gForkMode == FM_Data || (pb.fileParam.ioFlLgLen > 0 && gForkMode == FM_Smart)) {
  298.         // Open Data Fork
  299.         dWin->fork = FT_Data;
  300.         oe = HOpen(fsSpec->vRefNum,fsSpec->parID,fsSpec->name,fsRdPerm,&refNum);
  301.         if (oe == fnfErr) {
  302.             ParamText(fsSpec->name,"\pdata","\p","\p");
  303.             if (CautionAlert(NoForkALRT,NULL) != 2)
  304.                 return;
  305.             oe = HCreate(fsSpec->vRefNum,fsSpec->parID,fsSpec->name,
  306.                         pb.fileParam.ioFlFndrInfo.fdCreator,
  307.                         pb.fileParam.ioFlFndrInfo.fdType);
  308.             if (oe != noErr) {
  309.                 OSErrorAlert(ES_Caution, "HCreate", oe);
  310.                 return;
  311.             }
  312.             oe = HOpen(fsSpec->vRefNum,fsSpec->parID,fsSpec->name,fsRdPerm,&refNum);
  313.         }
  314.         if (oe != noErr) {
  315.             OSErrorAlert(ES_Caution, "HOpen", oe);
  316.             return;
  317.         }
  318.         dWin->fileSize = pb.fileParam.ioFlLgLen;
  319.     }
  320.     else {
  321.         // Open Resource Fork
  322.         dWin->fork = FT_Resource;
  323.         oe = HOpenRF(fsSpec->vRefNum,fsSpec->parID,fsSpec->name,fsRdPerm,&refNum);
  324.         if (oe == fnfErr) {
  325.             ParamText(fsSpec->name,"\presource","\p","\p");
  326.             if (CautionAlert(NoForkALRT,NULL) != 2)
  327.                 return;
  328.             HCreateResFile(fsSpec->vRefNum,fsSpec->parID,fsSpec->name);
  329.             if ((oe = ResError()) != noErr) {
  330.                 OSErrorAlert(ES_Caution, "HCreateResFile", oe);
  331.                 return;
  332.             }
  333.             oe = HOpenRF(fsSpec->vRefNum,fsSpec->parID,fsSpec->name,fsRdPerm,&refNum);
  334.         }
  335.         if (oe != noErr) {
  336.             OSErrorAlert(ES_Caution, "HOpenRF", oe);
  337.             return;
  338.         }
  339.         dWin->fileSize = pb.fileParam.ioFlRLgLen;
  340.     }
  341.  
  342.     dWin->refNum = refNum;
  343.  
  344.     workSpec = *fsSpec;
  345.     oe = FindFolder(-1, kTemporaryFolderType, kCreateFolder, 
  346.                     &workSpec.vRefNum,
  347.                     &workSpec.parID);
  348.     if (oe != noErr) {
  349.         OSErrorAlert(ES_Caution, "FindFolder", oe);
  350.         return;
  351.     }
  352.     if (workSpec.name[0] < 31) {
  353.         workSpec.name[0]++;
  354.         workSpec.name[workSpec.name[0]] = 'w';
  355.     }
  356.     else
  357.         workSpec.name[31] ^= 0x10;
  358.     InsureNameIsUnique(&workSpec);
  359.     oe = HCreate(workSpec.vRefNum,workSpec.parID,workSpec.name,CREATOR, '????');
  360.     if (oe != noErr) {
  361.         OSErrorAlert(ES_Caution, "HCreate", oe);
  362.         return;
  363.     }
  364.     oe = HOpen(workSpec.vRefNum,workSpec.parID,workSpec.name,fsRdWrPerm,&refNum);
  365.     if (oe != noErr) {
  366.         OSErrorAlert(ES_Caution, "HOpen", oe);
  367.         return;
  368.     }
  369.  
  370.     dWin->workSpec = workSpec;
  371.     dWin->workRefNum = refNum;
  372.     dWin->workBytesWritten = 0L;
  373.  
  374.     dWin->fileType = pb.fileParam.ioFlFndrInfo.fdType;
  375.     dWin->creator = pb.fileParam.ioFlFndrInfo.fdCreator;
  376.     dWin->creationDate =  pb.fileParam.ioFlCrDat;
  377.  
  378.     theWindow = InitObjectWindow(MainWIND, (ObjectWindowPtr) dWin,false);
  379.     SetRect(&r, 0, 0, MaxWindowWidth+SBarSize-1, gMaxHeight - 64);
  380.  
  381.     dWin->linesPerPage = ((r.bottom - SBarSize) - TopMargin - BotMargin - HeaderHeight)/LineHeight;
  382.  
  383.     if ((dWin->linesPerPage-1) * 16L > dWin->fileSize)
  384.         r.bottom -= LineHeight * (((dWin->linesPerPage-1) * 16L) - dWin->fileSize)/16;
  385.     if (r.bottom < SBarSize+TopMargin+BotMargin+HeaderHeight+LineHeight*3)
  386.         r.bottom = SBarSize+TopMargin+BotMargin+HeaderHeight+LineHeight*3;
  387.  
  388.     SizeWindow(theWindow,r.right-1,r.bottom,true);
  389.     SetRect(&r, 0, 0, MaxWindowWidth+SBarSize-1, gMaxHeight - 44);
  390.     OffsetRect(&r,3,41);
  391.     ((WStateData *) *((WindowPeek) theWindow)->dataHandle)->stdState = r;
  392.     SetWTitle(theWindow, fsSpec->name);
  393.     dWin->fsSpec = *fsSpec;
  394.     dWin->destSpec = dWin->fsSpec;
  395.  
  396.     ((ObjectWindowPtr) theWindow)->Draw = MyDraw;
  397.     ((ObjectWindowPtr) theWindow)->Idle = MyIdle;
  398.     ((ObjectWindowPtr) theWindow)->HandleClick = MyHandleClick;
  399.     ((ObjectWindowPtr) theWindow)->Dispose = DisposeEditWindow;
  400.     ((ObjectWindowPtr) theWindow)->ProcessKey = MyProcessKey;
  401.     ((ObjectWindowPtr) theWindow)->Save = SaveContents;
  402.     ((ObjectWindowPtr) theWindow)->SaveAs = SaveAsContents;
  403.     ((ObjectWindowPtr) theWindow)->Revert = RevertContents;
  404.     ((ObjectWindowPtr) theWindow)->Activate = MyActivate;
  405.     
  406.     SetRect(&offRect,0,0,MaxWindowWidth,gMaxHeight);
  407.  
  408.     dWin->bitMap.rowBytes = (((MaxWindowWidth-1)/32)+1)*4;
  409.     dWin->bitMap.baseAddr = NewPtrClear( (long) dWin->bitMap.rowBytes * gMaxHeight );
  410.     if (dWin->bitMap.baseAddr == NULL)
  411.         ErrorAlert(ES_Stop,"Not enough memory");
  412.     dWin->bitMap.bounds = offRect;
  413.  
  414.  
  415.     // Show the window
  416.     ShowWindow(theWindow);
  417.  
  418.     // Make it the current grafport
  419.     SetPort(theWindow);
  420.     
  421.     dWin->linesPerPage = ((theWindow->portRect.bottom - SBarSize) - TopMargin - BotMargin - HeaderHeight)/LineHeight;
  422.     dWin->startSel = dWin->endSel = 0L;
  423.     dWin->editMode = EM_Hex;
  424.  
  425.     SetupScrollBars(dWin);
  426.  
  427.     LoadFile(dWin);
  428. }
  429.  
  430. void DisposeEditWindow(WindowPtr theWindow)
  431. {
  432.     EditWindowPtr    dWin = (EditWindowPtr) theWindow;
  433.  
  434.     UnloadFile(dWin);
  435.     if (dWin->refNum)
  436.         FSClose(dWin->refNum);
  437.     if (dWin->workRefNum) {
  438.         FSClose(dWin->workRefNum);
  439.         HDelete(dWin->workSpec.vRefNum, dWin->workSpec.parID, dWin->workSpec.name);
  440.     }
  441.     if (dWin->bitMap.baseAddr) {
  442.         DisposePtr(dWin->bitMap.baseAddr);
  443.     }
  444.     DefaultDispose(theWindow);
  445.     MyAdjustMenus();
  446. }
  447.  
  448. Boolean    CloseEditWindow(WindowPtr theWindow)
  449. {
  450.     Str63            fileName;
  451.     EditWindowPtr    dWin = (EditWindowPtr) theWindow;
  452.  
  453.     MySetCursor(C_Arrow);
  454.  
  455.     if (dWin->dirtyFlag) {
  456.         GetWTitle(theWindow, fileName);
  457.         ParamText(fileName, "\p","\p","\p");
  458.         switch (Alert(SaveChangesALRT, NULL)) {
  459.         case OK:        
  460.             SaveContents(theWindow);    
  461.             break;
  462.         case Cancel:
  463.             return false;
  464.         case 3:
  465.             // Discard
  466.             break;
  467.         }
  468.     }
  469.     ((ObjectWindowPtr) dWin)->Dispose(theWindow);
  470.     return true;
  471. }
  472.  
  473. Boolean CloseAllEditWindows()
  474. {
  475.     WindowPeek    wp;
  476.     wp = (WindowPeek) FrontWindow();
  477.     while (wp) {
  478.         if (wp->windowKind < 0)
  479.              CloseDeskAcc(wp->windowKind);
  480.         else if (wp->refCon == MyWindowID) {
  481.             if (!CloseEditWindow((WindowPtr) wp))
  482.                 return false;
  483.         }
  484.         else if ((WindowPtr) wp == gSearchWin) {
  485.             DisposDialog(gSearchWin);
  486.             gSearchWin = NULL;
  487.         }
  488.         else
  489.             return false;
  490.         wp = (WindowPeek) FrontWindow();
  491.     }
  492.     return true;
  493. }
  494.  
  495. // Respond to an update event - BeginUpdate has already been called.
  496. //
  497.  
  498. void MyDraw(WindowPtr theWindow)
  499. {
  500.     RgnHandle        rg1,rg2,rg3;
  501.     Rect            r3;
  502.     EditWindowPtr    dWin = (EditWindowPtr) theWindow;
  503.  
  504.     rg1 = NewRgn();
  505.     rg2 = NewRgn();
  506.     rg3 = NewRgn();
  507.     RectRgn(rg1, &theWindow->portRect);
  508.     RectRgn(rg2, &dWin->bitMap.bounds);
  509.     r3 = theWindow->portRect;
  510.     r3.right -= SBarSize-1;
  511.     r3.bottom -= SBarSize-1;
  512.     RectRgn(rg3, &r3);
  513.     SectRgn(rg2,rg3,rg2);    // Intersection of offscreen and valid content area
  514.     DiffRgn(rg1,rg2,rg1);    // Subtract from whole content area
  515.     EraseRgn(rg1);
  516.     DisposeRgn(rg1);
  517.     DisposeRgn(rg2);
  518.     DisposeRgn(rg3);
  519.     // Draw the grow icon in the corner
  520.     // EraseRect(&theWindow->portRect);
  521.     DrawControls(theWindow);
  522.     DrawGrowIcon(theWindow);
  523.     DrawPage((EditWindowPtr) theWindow);
  524.     UpdateOnscreen(theWindow);
  525. }
  526.  
  527. void UpdateOnscreen(WindowPtr theWindow)
  528. {
  529.     Rect            r1,r2,r3;
  530.     EditWindowPtr    dWin = (EditWindowPtr) theWindow;
  531.  
  532.     gCursorFlag = false;
  533.     r1 = dWin->bitMap.bounds;
  534.     r2 = theWindow->portRect;
  535.     r2.right -= SBarSize - 1;
  536.     r2.bottom -= SBarSize - 1;
  537.     SectRect(&r1,&r2,&r3);
  538.     SetPort(theWindow);
  539.     CopyBits(&dWin->bitMap,&theWindow->portBits,&r3,&r3,srcCopy,0L);
  540.     if (dWin->endSel > dWin->startSel && 
  541.         dWin->endSel >= dWin->editOffset &&
  542.         dWin->startSel < dWin->editOffset+(dWin->linesPerPage<<4)) 
  543.         InvertSelection(dWin);
  544. }
  545.  
  546. void MyIdle(WindowPtr theWin, EventRecord *er)
  547. {
  548.     EditWindowPtr    dWin = (EditWindowPtr) theWin;
  549.     Boolean            frontWindowFlag;
  550.     Point            w;
  551.     frontWindowFlag = (theWin == FrontWindow() &&
  552.                         dWin->oWin.active);
  553.     if (frontWindowFlag) {
  554.         w = er->where;
  555.         SetPort(theWin);
  556.         GlobalToLocal(&w);
  557.         if (w.v >= HeaderHeight+TopMargin && 
  558.             w.v < HeaderHeight+TopMargin+(dWin->linesPerPage*LineHeight))
  559.         {
  560.                 if (w.h >= AddrPos+CharPos(HexStart) &&
  561.                     w.h < AddrPos+CharPos(HexStart)+(HexWidth<<4)) 
  562.                     MySetCursor(C_IBeam);
  563.                 else if (w.h >= AddrPos+CharPos(AsciiStart) &&
  564.                          w.h < AddrPos+CharPos(AsciiStart)+(CharWidth<<4))
  565.                     MySetCursor(C_IBeam);
  566.                 else
  567.                     MySetCursor(C_Arrow);
  568.         }
  569.         else
  570.             MySetCursor(C_Arrow);
  571.  
  572.         if (dWin->startSel == dWin->endSel) {
  573.             if ((Ticks & 0x1F) < 0x10)
  574.                 CursorOn(theWin);
  575.             else
  576.                 CursorOff(theWin);
  577.         }
  578.         if (gScrapCount != ScrapInfo.scrapCount) {
  579.             EditChunk    **nc;
  580.             Handle        h;
  581.             long        size,offset;
  582.             size = GetScrap(NULL, 'TEXT', &offset);
  583.             if (size > 0) {
  584.                 nc = NewChunk(size,0,0,CT_Unwritten);
  585.                 if (nc == NULL)
  586.                     ErrorAlert(ES_Caution,"Not enough memory for desktop scrap");
  587.                 else {
  588.                     ReleaseEditScrap(dWin, &gScrapChunk);
  589.                     gScrapChunk = nc;
  590.                     GetScrap((*gScrapChunk)->data,'TEXT',&offset);
  591.                     (*gScrapChunk)->lastCtr = 1;    // Flag as external
  592.                 }
  593.             }
  594.             gScrapCount = ScrapInfo.scrapCount;
  595.         }
  596.     }
  597. }
  598.  
  599.  
  600. // Respond to a mouse-click - highlight cells until the user releases the button
  601. //
  602. void MyHandleClick(WindowPtr theWin, Point where, EventRecord *er)
  603. {
  604.     Point    w;
  605.     long    pos;
  606.     EditWindowPtr    dWin = (EditWindowPtr) theWin;
  607.     long    anchorPos = -1,sPos,ePos;
  608.  
  609.     SetPort(theWin);
  610.     w = where;
  611.     GlobalToLocal(&w);
  612.     if (HandleControlClick(theWin,w))
  613.         return;
  614.     // Else handle editing chore
  615.     CursorOff(theWin);
  616.     if (w.v >= HeaderHeight+TopMargin && 
  617.         w.v < HeaderHeight+TopMargin+(dWin->linesPerPage*LineHeight))
  618.     {
  619.         do {
  620.             AutoScroll(dWin, w);
  621.  
  622.             if (w.h >= AddrPos+CharPos(HexStart) &&
  623.                 w.h < AddrPos+CharPos(HexStart)+(HexWidth<<4)) 
  624.             {
  625.  
  626.                 pos = ((w.v - (HeaderHeight+TopMargin))/LineHeight)*16 +
  627.                       (w.h - (AddrPos+CharPos(HexStart))+12) / HexWidth;
  628.                 dWin->editMode = EM_Hex;
  629.             }
  630.             else if (w.h >= AddrPos+CharPos(AsciiStart) &&
  631.                      w.h < AddrPos+CharPos(AsciiStart)+(CharWidth<<4))
  632.             {
  633.                 pos = ((w.v - (HeaderHeight+TopMargin))/LineHeight)*16 +
  634.                       (w.h - (AddrPos+CharPos(AsciiStart))+3) / CharWidth;
  635.                 dWin->editMode = EM_Ascii;
  636.             }
  637.             else {
  638.                 goto GetMouseLabel;
  639.             }
  640.             pos += dWin->editOffset;
  641.             if (pos < dWin->editOffset)
  642.                 pos = dWin->editOffset;
  643.             if (pos > dWin->editOffset+(dWin->linesPerPage<<4))
  644.                 pos = dWin->editOffset+(dWin->linesPerPage<<4);
  645.             if (pos > dWin->fileSize)
  646.                 pos = dWin->fileSize;
  647.             if (anchorPos == -1) {
  648.                 if (er->modifiers & shiftKey)
  649.                     anchorPos = (pos < dWin->startSel)? dWin->endSel : dWin->startSel;
  650.                 else
  651.                     anchorPos = pos;
  652.             }
  653.             sPos = pos < anchorPos? pos : anchorPos;
  654.             ePos = pos > anchorPos? pos : anchorPos;
  655.             if (ePos > dWin->fileSize)
  656.                 ePos = dWin->fileSize;
  657.  
  658.             if (sPos != dWin->startSel ||
  659.                 ePos != dWin->endSel) {
  660.                 dWin->startSel = sPos;
  661.                 dWin->endSel = ePos;
  662.                 UpdateOnscreen(theWin);
  663.             }
  664.  
  665.     GetMouseLabel:
  666.             GetMouse(&w);
  667.         } while (WaitMouseUp());
  668.     }
  669. }
  670.  
  671. void DrawHeader(EditWindowPtr dWin, Rect *r)
  672. {
  673.     TextFont(monaco);
  674.     TextSize(9);
  675.     TextFace(bold);
  676.     TextMode(srcCopy);
  677.  
  678.     MoveTo(r->left,r->top+HeaderHeight-1);
  679.     LineTo(r->right,r->top+HeaderHeight-1);
  680.  
  681.     MoveTo(20, r->top+HeaderHeight-DescendHeight-2);
  682.     if (gPrefs.decimalAddr)
  683.         sprintf(gBuffer,"Length: %7ld    Type: %4.4s    Creator: %4.4s    Fork: %s", 
  684.             dWin->fileSize,&dWin->fileType, &dWin->creator,
  685.             ((dWin->fork == FT_Data)? "data" : "rsrc"));
  686.     else
  687.         sprintf(gBuffer,"Length: %6lXh    Type: %4.4s    Creator: %4.4s    Fork: %s", 
  688.             dWin->fileSize,&dWin->fileType, &dWin->creator,
  689.             ((dWin->fork == FT_Data)? "data" : "rsrc"));
  690.     DrawText(gBuffer,0,strlen(gBuffer));
  691. }
  692.  
  693. void DrawFooter(EditWindowPtr dWin, Rect *r, short pageNbr, short nbrPages)
  694. {
  695.     unsigned long    tim;
  696.     DateTimeRec        dat;
  697.     Str31            fileName;
  698.  
  699.     TextFont(monaco);
  700.     TextSize(9);
  701.     TextFace(0);
  702.     TextMode(srcCopy);
  703.  
  704.     GetDateTime(&tim);
  705.     Secs2Date(tim,&dat);
  706.  
  707.     MoveTo(r->left,r->top);
  708.     LineTo(r->right,r->top);
  709.  
  710.     sprintf(gBuffer, "%02d/%02d/%02d %02d:%02d",
  711.         dat.month,dat.day,dat.year-1900,dat.hour,dat.minute);
  712.  
  713.     MoveTo(20, r->top+FooterHeight-DescendHeight-2);
  714.     DrawText(gBuffer,0,strlen(gBuffer));
  715.  
  716.     GetWTitle((WindowPtr) dWin, fileName);
  717.     sprintf(gBuffer,"File: %.*s", fileName[0],&fileName[1]);
  718.     MoveTo((r->left+r->right)/2 - TextWidth(gBuffer,0,strlen(gBuffer))/2,
  719.              r->top+FooterHeight-DescendHeight-2);
  720.     DrawText(gBuffer,0,strlen(gBuffer));
  721.     
  722.     sprintf(gBuffer,"%d of %d",pageNbr,nbrPages);
  723.     MoveTo(r->right - TextWidth(gBuffer,0,strlen(gBuffer)) - 8, 
  724.             r->top+FooterHeight-DescendHeight-2);
  725.     DrawText(gBuffer,0,strlen(gBuffer));
  726. }
  727.  
  728. void DrawDump(EditWindowPtr dWin, Rect *r, long sAddr, long eAddr)
  729. {
  730.     short    y;
  731.     short    hexPos;
  732.     short    asciiPos;
  733.     register short    i,ch,ch1,ch2;
  734.     long    addr;
  735.     TextFont(monaco);
  736.     TextSize(9);
  737.     TextFace(0);
  738.     TextMode(srcCopy);
  739.  
  740.     addr = sAddr - (sAddr % 16);
  741.     for (y = r->top; y < r->bottom && addr < eAddr; y += LineHeight) {
  742.         MoveTo(AddrPos,y);
  743.         if (gPrefs.decimalAddr)
  744.             sprintf(gBuffer,"%7ld: ", addr);
  745.         else
  746.             sprintf(gBuffer,"%06lX:  ", addr);
  747.         hexPos = HexStart;
  748.         asciiPos = AsciiStart;
  749.         for (i = 16; i; --i,++addr) {
  750.             if (addr >= sAddr && addr < eAddr) {
  751.                 ch = GetByte(dWin, addr);
  752.                 ch1 = ch2 = ch;
  753.                 ch1 >>= 4;
  754.                 ch2 &= 0x0F;
  755.                 gBuffer[hexPos++] = ch1 + ((ch1 < 10)? '0' : ('A'-10));
  756.                 gBuffer[hexPos++] = ch2 + ((ch2 < 10)? '0' : ('A'-10));
  757.                 gBuffer[hexPos++] = ' ';
  758.                 gBuffer[asciiPos++] = ((ch >= ' ' && ch <= gHighChar)? ch : '.');
  759.             }
  760.             else {
  761.                 gBuffer[hexPos++] = ' ';
  762.                 gBuffer[hexPos++] = ' ';
  763.                 gBuffer[hexPos++] = ' ';
  764.                 gBuffer[asciiPos++] = ' ';
  765.             }
  766.         }
  767.         gBuffer[57] = ' ';
  768.         gBuffer[58] = ' ';
  769.         MoveTo(AddrPos,y);
  770.         DrawText(gBuffer,0,75);
  771.     }
  772. }
  773.  
  774. void DrawPage(EditWindowPtr dWin)
  775. {
  776.     GrafPtr            savePort;
  777.     Rect            r;
  778.     BitMap            realBits;
  779.  
  780. #if PROFILE
  781.     _profile = 1;
  782. #endif
  783.     GetPort(&savePort);
  784.     SetPort((GrafPtr) dWin);
  785.  
  786.     realBits = ((GrafPtr) dWin)->portBits;
  787.     SetPortBits(&dWin->bitMap);
  788.  
  789.     r = ((WindowPtr) dWin)->portRect;
  790.     r.right -= (SBarSize - 1);
  791. //    r.bottom -= (SBarSize - 1);
  792.  
  793.     if (r.right - r.left > dWin->bitMap.bounds.right - dWin->bitMap.bounds.left ||
  794.         r.bottom - r.top > dWin->bitMap.bounds.bottom - dWin->bitMap.bounds.top)
  795.         DebugStr("\pOy!");
  796.  
  797.     EraseRect(&r);
  798.  
  799.     DrawHeader(dWin, &r);
  800.  
  801.     r.top += (HeaderHeight+TopMargin+LineHeight-DescendHeight);
  802.     r.bottom -= (SBarSize+DescendHeight+BotMargin);
  803.  
  804.     DrawDump(dWin, &r, dWin->editOffset, dWin->fileSize);
  805.  
  806.     // if (dWin->endSel > dWin->startSel && 
  807.     //    dWin->endSel >= dWin->editOffset &&
  808.     //    dWin->startSel < dWin->editOffset+(dWin->linesPerPage<<4)) 
  809.     //    InvertSelection(dWin);
  810.  
  811.     SetPortBits(&realBits);
  812.     SetPort(savePort);
  813.  
  814. #if PROFILE
  815.     _profile = 0;
  816. #endif
  817. }
  818.  
  819. void InvertSelection(EditWindowPtr    dWin)
  820. {
  821.     // Invert Selection
  822.     Rect    r;
  823.     long    x;
  824.     long    start,end;
  825.     short    startX,endX;
  826.     Boolean    frontFlag;
  827.  
  828.     frontFlag = ((WindowPtr) dWin == FrontWindow() &&
  829.                  dWin->oWin.active);
  830.  
  831.     if (dWin->endSel <= dWin->startSel)
  832.         return;
  833.  
  834.     start = dWin->startSel - dWin->editOffset;
  835.     if (start < 0)
  836.         start = 0;
  837.     end = (dWin->endSel-1) - dWin->editOffset;
  838.     if (end > (dWin->linesPerPage<<4)-1)
  839.         end = (dWin->linesPerPage<<4)-1;
  840.  
  841.     PenMode(patXor);
  842.     
  843.     startX = ColNbr(start);
  844.     endX = ColNbr(end);
  845.  
  846.     if (!frontFlag) {
  847.         if (LineNbr(start) < LineNbr(end)) {
  848.             // Invert Hex
  849.             r.top = HeaderHeight+TopMargin+LineNbr(start)*LineHeight;
  850.             r.bottom = r.top+LineHeight;
  851.             r.left = AddrPos+CharPos(HexStart)+HexPos(startX)-3;
  852.             r.right = AddrPos+CharPos(HexStart)+HexPos(16)-3;
  853.  
  854.             MoveTo(AddrPos+CharPos(HexStart)-3,r.bottom);
  855.             if (gColorQDFlag)
  856.                 HiliteMode &= ~(1 << hiliteBit);    // Hilite using Hilite Color
  857.             LineTo(r.left,r.bottom);
  858.             if (gColorQDFlag)
  859.                 HiliteMode &= ~(1 << hiliteBit);    // Hilite using Hilite Color
  860.             LineTo(r.left,r.top);
  861.             if (dWin->startSel >= dWin->editOffset) {
  862.                 if (gColorQDFlag)
  863.                 HiliteMode &= ~(1 << hiliteBit);    // Hilite using Hilite Color
  864.                 LineTo(r.right,r.top);
  865.             }
  866.             else
  867.                 MoveTo(r.right,r.top);
  868.             if (gColorQDFlag)
  869.                 HiliteMode &= ~(1 << hiliteBit);    // Hilite using Hilite Color
  870.             LineTo(r.right,r.bottom);
  871.  
  872.             // Outline Box around Ascii
  873.             r.left = AddrPos+CharPos(AsciiStart)+CharPos(startX)-1;
  874.             r.right = AddrPos+CharPos(AsciiStart)+CharPos(16);
  875.             
  876.             MoveTo(AddrPos+CharPos(AsciiStart),r.bottom);
  877.             if (gColorQDFlag)
  878.                 HiliteMode &= ~(1 << hiliteBit);    // Hilite using Hilite Color
  879.             LineTo(r.left,r.bottom);
  880.  
  881.             if (gColorQDFlag)
  882.                 HiliteMode &= ~(1 << hiliteBit);    // Hilite using Hilite Color
  883.             LineTo(r.left,r.top);
  884.             if (dWin->startSel >= dWin->editOffset) {
  885.                 if (gColorQDFlag)
  886.                 HiliteMode &= ~(1 << hiliteBit);    // Hilite using Hilite Color
  887.                 LineTo(r.right,r.top);
  888.             }
  889.             else
  890.                 MoveTo(r.right,r.top);
  891.             if (gColorQDFlag)
  892.                 HiliteMode &= ~(1 << hiliteBit);    // Hilite using Hilite Color
  893.             LineTo(r.right,r.bottom);
  894.  
  895.             if (LineNbr(start) < LineNbr(end)-1) {
  896.                 r.top = HeaderHeight+TopMargin+LineNbr(start)*LineHeight+LineHeight;
  897.                 r.bottom = HeaderHeight+TopMargin+LineNbr(end)*LineHeight;
  898.                 r.left = AddrPos+CharPos(HexStart)-3;
  899.                 r.right = AddrPos+CharPos(HexStart)+HexPos(16)-3;
  900.                 MoveTo(r.left,r.top);
  901.                 if (gColorQDFlag)
  902.                 HiliteMode &= ~(1 << hiliteBit);    // Hilite using Hilite Color
  903.                 LineTo(r.left,r.bottom);
  904.                 MoveTo(r.right,r.top);
  905.                 if (gColorQDFlag)
  906.                 HiliteMode &= ~(1 << hiliteBit);    // Hilite using Hilite Color
  907.                 LineTo(r.right,r.bottom);
  908.  
  909.                 r.left = AddrPos+CharPos(AsciiStart)-1;
  910.                 r.right = AddrPos+CharPos(AsciiStart)+CharPos(16);
  911.                 MoveTo(r.left,r.top);
  912.                 if (gColorQDFlag)
  913.                 HiliteMode &= ~(1 << hiliteBit);    // Hilite using Hilite Color
  914.                 LineTo(r.left,r.bottom);
  915.                 MoveTo(r.right,r.top);
  916.                 if (gColorQDFlag)
  917.                 HiliteMode &= ~(1 << hiliteBit);    // Hilite using Hilite Color
  918.                 LineTo(r.right,r.bottom);
  919.             }
  920.             r.top = HeaderHeight+TopMargin+LineNbr(end)*LineHeight;
  921.             r.bottom = r.top+LineHeight;
  922.             r.left = AddrPos+CharPos(HexStart)-3;
  923.             r.right = AddrPos+CharPos(HexStart)+HexPos(endX)+HexWidth-3;
  924.             MoveTo(r.left,r.top);
  925.             if (gColorQDFlag)
  926.                 HiliteMode &= ~(1 << hiliteBit);    // Hilite using Hilite Color
  927.             LineTo(r.left,r.bottom);
  928.             if (dWin->endSel < dWin->editOffset+dWin->linesPerPage*16) {
  929.                 if (gColorQDFlag)
  930.                 HiliteMode &= ~(1 << hiliteBit);    // Hilite using Hilite Color
  931.                 LineTo(r.right,r.bottom);
  932.             }
  933.             else
  934.                 MoveTo(r.right,r.bottom);
  935.             if (gColorQDFlag)
  936.                 HiliteMode &= ~(1 << hiliteBit);    // Hilite using Hilite Color
  937.             LineTo(r.right,r.top);
  938.             if (gColorQDFlag)
  939.                 HiliteMode &= ~(1 << hiliteBit);    // Hilite using Hilite Color
  940.             LineTo(AddrPos+CharPos(HexStart)+HexPos(16)-3,r.top);
  941.  
  942.             r.left = AddrPos+CharPos(AsciiStart)-1;
  943.             r.right = AddrPos+CharPos(AsciiStart)+CharPos(endX)+CharWidth-1;
  944.             MoveTo(r.left,r.top);
  945.             if (gColorQDFlag)
  946.                 HiliteMode &= ~(1 << hiliteBit);    // Hilite using Hilite Color
  947.             LineTo(r.left,r.bottom-1);
  948.             if (dWin->endSel < dWin->editOffset+dWin->linesPerPage*16) {
  949.                 if (gColorQDFlag)
  950.                 HiliteMode &= ~(1 << hiliteBit);    // Hilite using Hilite Color
  951.                 LineTo(r.right,r.bottom-1);
  952.             }
  953.             else
  954.                 MoveTo(r.right,r.bottom-1);
  955.             if (gColorQDFlag)
  956.                 HiliteMode &= ~(1 << hiliteBit);    // Hilite using Hilite Color
  957.             LineTo(r.right,r.top);
  958.             if (gColorQDFlag)
  959.                 HiliteMode &= ~(1 << hiliteBit);    // Hilite using Hilite Color
  960.             LineTo(AddrPos+CharPos(AsciiStart)+CharPos(16),r.top);
  961.         }
  962.         else {
  963.             r.top = HeaderHeight+TopMargin+LineNbr(start)*LineHeight;
  964.             r.bottom = r.top+LineHeight;
  965.             r.left = AddrPos+CharPos(HexStart)+HexPos(startX)-3;
  966.             r.right = AddrPos+CharPos(HexStart)+HexPos(endX)+HexWidth-3;
  967.             MoveTo(r.left,r.top);
  968.             if (gColorQDFlag)
  969.                 HiliteMode &= ~(1 << hiliteBit);    // Hilite using Hilite Color
  970.             LineTo(r.left,r.bottom);
  971.             if (dWin->endSel < dWin->editOffset+dWin->linesPerPage*16) {
  972.                 if (gColorQDFlag)
  973.                 HiliteMode &= ~(1 << hiliteBit);    // Hilite using Hilite Color
  974.                 LineTo(r.right,r.bottom);
  975.             }
  976.             else
  977.                 MoveTo(r.right,r.bottom);
  978.             if (gColorQDFlag)
  979.                 HiliteMode &= ~(1 << hiliteBit);    // Hilite using Hilite Color
  980.             LineTo(r.right,r.top);
  981.             if (dWin->startSel >= dWin->editOffset) {
  982.                 if (gColorQDFlag)
  983.                 HiliteMode &= ~(1 << hiliteBit);    // Hilite using Hilite Color
  984.                 LineTo(r.left,r.top);
  985.             }
  986.  
  987.             r.left = AddrPos+CharPos(AsciiStart)+CharPos(startX)-1;
  988.             r.right = AddrPos+CharPos(AsciiStart)+CharPos(endX)+CharWidth-1;
  989.  
  990.             MoveTo(r.left,r.top);
  991.             if (gColorQDFlag)
  992.                 HiliteMode &= ~(1 << hiliteBit);    // Hilite using Hilite Color
  993.             LineTo(r.left,r.bottom-1);
  994.             if (dWin->endSel < dWin->editOffset+dWin->linesPerPage*16) {
  995.                 if (gColorQDFlag)
  996.                 HiliteMode &= ~(1 << hiliteBit);    // Hilite using Hilite Color
  997.                 LineTo(r.right,r.bottom-1);
  998.             }
  999.             else
  1000.                 MoveTo(r.right,r.bottom-1);
  1001.             if (gColorQDFlag)
  1002.                 HiliteMode &= ~(1 << hiliteBit);    // Hilite using Hilite Color
  1003.             LineTo(r.right,r.top);
  1004.             if (dWin->startSel >= dWin->editOffset) {
  1005.                 if (gColorQDFlag)
  1006.                 HiliteMode &= ~(1 << hiliteBit);    // Hilite using Hilite Color
  1007.                 LineTo(r.left,r.top);
  1008.             }
  1009.         }
  1010.     }
  1011.     else {
  1012.         if (dWin->editMode == EM_Hex) {
  1013.             if (LineNbr(start) < LineNbr(end)) {
  1014.     
  1015.                 // Invert Hex
  1016.                 r.top = HeaderHeight+TopMargin+LineNbr(start)*LineHeight;
  1017.                 r.bottom = r.top+LineHeight;
  1018.                 r.left = AddrPos+CharPos(HexStart)+HexPos(startX)-3;
  1019.                 r.right = AddrPos+CharPos(HexStart)+HexPos(16)-3;
  1020.     
  1021.                 if (gColorQDFlag)
  1022.                 HiliteMode &= ~(1 << hiliteBit);    // Hilite using Hilite Color
  1023.                 InvertRect(&r);
  1024.     
  1025.     
  1026.                 // Outline Box around Ascii
  1027.                 r.left = AddrPos+CharPos(AsciiStart)+CharPos(startX)-1;
  1028.                 r.right = AddrPos+CharPos(AsciiStart)+CharPos(16);
  1029.                 
  1030.                 MoveTo(AddrPos+CharPos(AsciiStart),r.bottom);
  1031.                 if (gColorQDFlag)
  1032.                 HiliteMode &= ~(1 << hiliteBit);    // Hilite using Hilite Color
  1033.                 LineTo(r.left,r.bottom);
  1034.     
  1035.                 if (gColorQDFlag)
  1036.                 HiliteMode &= ~(1 << hiliteBit);    // Hilite using Hilite Color
  1037.                 LineTo(r.left,r.top);
  1038.                 if (dWin->startSel >= dWin->editOffset) {
  1039.                     if (gColorQDFlag)
  1040.                 HiliteMode &= ~(1 << hiliteBit);    // Hilite using Hilite Color
  1041.                     LineTo(r.right,r.top);
  1042.                 }
  1043.                 else
  1044.                     MoveTo(r.right,r.top);
  1045.                 if (gColorQDFlag)
  1046.                 HiliteMode &= ~(1 << hiliteBit);    // Hilite using Hilite Color
  1047.                 LineTo(r.right,r.bottom);
  1048.     
  1049.                 if (LineNbr(start) < LineNbr(end)-1) {
  1050.                     r.top = HeaderHeight+TopMargin+LineNbr(start)*LineHeight+LineHeight;
  1051.                     r.bottom = HeaderHeight+TopMargin+LineNbr(end)*LineHeight;
  1052.                     r.left = AddrPos+CharPos(HexStart)-3;
  1053.                     r.right = AddrPos+CharPos(HexStart)+HexPos(16)-3;
  1054.                     if (gColorQDFlag)
  1055.                 HiliteMode &= ~(1 << hiliteBit);    // Hilite using Hilite Color
  1056.                     InvertRect(&r);
  1057.     
  1058.                     r.left = AddrPos+CharPos(AsciiStart)-1;
  1059.                     r.right = AddrPos+CharPos(AsciiStart)+CharPos(16);
  1060.                     MoveTo(r.left,r.top);
  1061.                     if (gColorQDFlag)
  1062.                 HiliteMode &= ~(1 << hiliteBit);    // Hilite using Hilite Color
  1063.                     LineTo(r.left,r.bottom);
  1064.                     MoveTo(r.right,r.top);
  1065.                     if (gColorQDFlag)
  1066.                 HiliteMode &= ~(1 << hiliteBit);    // Hilite using Hilite Color
  1067.                     LineTo(r.right,r.bottom);
  1068.                 }
  1069.                 r.top = HeaderHeight+TopMargin+LineNbr(end)*LineHeight;
  1070.                 r.bottom = r.top+LineHeight;
  1071.                 r.left = AddrPos+CharPos(HexStart)-3;
  1072.                 r.right = AddrPos+CharPos(HexStart)+HexPos(endX)+HexWidth-3;
  1073.                 if (gColorQDFlag)
  1074.                 HiliteMode &= ~(1 << hiliteBit);    // Hilite using Hilite Color
  1075.                 InvertRect(&r);
  1076.     
  1077.                 r.left = AddrPos+CharPos(AsciiStart)-1;
  1078.                 r.right = AddrPos+CharPos(AsciiStart)+CharPos(endX)+CharWidth-1;
  1079.                 MoveTo(r.left,r.top);
  1080.                 if (gColorQDFlag)
  1081.                 HiliteMode &= ~(1 << hiliteBit);    // Hilite using Hilite Color
  1082.                 LineTo(r.left,r.bottom-1);
  1083.                 if (dWin->endSel < dWin->editOffset+dWin->linesPerPage*16) {
  1084.                     if (gColorQDFlag)
  1085.                 HiliteMode &= ~(1 << hiliteBit);    // Hilite using Hilite Color
  1086.                     LineTo(r.right,r.bottom-1);
  1087.                 }
  1088.                 else
  1089.                     MoveTo(r.right,r.bottom-1);
  1090.                 if (gColorQDFlag)
  1091.                 HiliteMode &= ~(1 << hiliteBit);    // Hilite using Hilite Color
  1092.                 LineTo(r.right,r.top);
  1093.                 if (gColorQDFlag)
  1094.                 HiliteMode &= ~(1 << hiliteBit);    // Hilite using Hilite Color
  1095.                 LineTo(AddrPos+CharPos(AsciiStart)+CharPos(16),r.top);
  1096.             }
  1097.             else {
  1098.                 r.top = HeaderHeight+TopMargin+LineNbr(start)*LineHeight;
  1099.                 r.bottom = r.top+LineHeight;
  1100.                 r.left = AddrPos+CharPos(HexStart)+HexPos(startX)-3;
  1101.                 r.right = AddrPos+CharPos(HexStart)+HexPos(endX)+HexWidth-3;
  1102.                 if (gColorQDFlag)
  1103.                 HiliteMode &= ~(1 << hiliteBit);    // Hilite using Hilite Color
  1104.                 InvertRect(&r);
  1105.     
  1106.                 r.left = AddrPos+CharPos(AsciiStart)+CharPos(startX)-1;
  1107.                 r.right = AddrPos+CharPos(AsciiStart)+CharPos(endX)+CharWidth-1;
  1108.     
  1109.                 MoveTo(r.left,r.top);
  1110.                 if (gColorQDFlag)
  1111.                 HiliteMode &= ~(1 << hiliteBit);    // Hilite using Hilite Color
  1112.                 LineTo(r.left,r.bottom-1);
  1113.                 if (dWin->endSel < dWin->editOffset+dWin->linesPerPage*16) {
  1114.                     if (gColorQDFlag)
  1115.                 HiliteMode &= ~(1 << hiliteBit);    // Hilite using Hilite Color
  1116.                     LineTo(r.right,r.bottom-1);
  1117.                 }
  1118.                 else
  1119.                     MoveTo(r.right,r.bottom-1);
  1120.                 if (gColorQDFlag)
  1121.                 HiliteMode &= ~(1 << hiliteBit);    // Hilite using Hilite Color
  1122.                 LineTo(r.right,r.top);
  1123.                 if (dWin->startSel >= dWin->editOffset) {
  1124.                     if (gColorQDFlag)
  1125.                 HiliteMode &= ~(1 << hiliteBit);    // Hilite using Hilite Color
  1126.                     LineTo(r.left,r.top);
  1127.                 }
  1128.             }
  1129.         }
  1130.         else {
  1131.             // Ascii Mode!!
  1132.             //
  1133.             if (LineNbr(start) < LineNbr(end)) {
  1134.     
  1135.                 // Invert Hex
  1136.                 r.top = HeaderHeight+TopMargin+LineNbr(start)*LineHeight;
  1137.                 r.bottom = r.top+LineHeight;
  1138.                 r.left = AddrPos+CharPos(HexStart)+HexPos(startX)-3;
  1139.                 r.right = AddrPos+CharPos(HexStart)+HexPos(16)-3;
  1140.     
  1141.                 MoveTo(AddrPos+CharPos(HexStart)-3,r.bottom);
  1142.                 if (gColorQDFlag)
  1143.                 HiliteMode &= ~(1 << hiliteBit);    // Hilite using Hilite Color
  1144.                 LineTo(r.left,r.bottom);
  1145.                 if (gColorQDFlag)
  1146.                 HiliteMode &= ~(1 << hiliteBit);    // Hilite using Hilite Color
  1147.                 LineTo(r.left,r.top);
  1148.                 if (dWin->startSel >= dWin->editOffset) {
  1149.                     if (gColorQDFlag)
  1150.                 HiliteMode &= ~(1 << hiliteBit);    // Hilite using Hilite Color
  1151.                     LineTo(r.right,r.top);
  1152.                 }
  1153.                 else
  1154.                     MoveTo(r.right,r.top);
  1155.                 if (gColorQDFlag)
  1156.                 HiliteMode &= ~(1 << hiliteBit);    // Hilite using Hilite Color
  1157.                 LineTo(r.right,r.bottom);
  1158.     
  1159.                 // Outline Box around Ascii
  1160.                 r.left = AddrPos+CharPos(AsciiStart)+CharPos(startX)-1;
  1161.                 r.right = AddrPos+CharPos(AsciiStart)+CharPos(16)-1;
  1162.                 
  1163.                 if (gColorQDFlag)
  1164.                 HiliteMode &= ~(1 << hiliteBit);    // Hilite using Hilite Color
  1165.                 InvertRect(&r);
  1166.     
  1167.                 if (LineNbr(start) < LineNbr(end)-1) {
  1168.                     r.top = HeaderHeight+TopMargin+LineNbr(start)*LineHeight+LineHeight;
  1169.                     r.bottom = HeaderHeight+TopMargin+LineNbr(end)*LineHeight;
  1170.                     r.left = AddrPos+CharPos(HexStart)-3;
  1171.                     r.right = AddrPos+CharPos(HexStart)+HexPos(16)-3;
  1172.                     MoveTo(r.left,r.top);
  1173.                     if (gColorQDFlag)
  1174.                 HiliteMode &= ~(1 << hiliteBit);    // Hilite using Hilite Color
  1175.                     LineTo(r.left,r.bottom);
  1176.                     MoveTo(r.right,r.top);
  1177.                     if (gColorQDFlag)
  1178.                 HiliteMode &= ~(1 << hiliteBit);    // Hilite using Hilite Color
  1179.                     LineTo(r.right,r.bottom);
  1180.     
  1181.                     r.left = AddrPos+CharPos(AsciiStart)-1;
  1182.                     r.right = AddrPos+CharPos(AsciiStart)+CharPos(16)-1;
  1183.                     if (gColorQDFlag)
  1184.                 HiliteMode &= ~(1 << hiliteBit);    // Hilite using Hilite Color
  1185.                     InvertRect(&r);
  1186.                 }
  1187.                 r.top = HeaderHeight+TopMargin+LineNbr(end)*LineHeight;
  1188.                 r.bottom = r.top+LineHeight;
  1189.                 r.left = AddrPos+CharPos(HexStart)-3;
  1190.                 r.right = AddrPos+CharPos(HexStart)+HexPos(endX)+HexWidth-3;
  1191.                 MoveTo(r.left,r.top);
  1192.                 if (gColorQDFlag)
  1193.                 HiliteMode &= ~(1 << hiliteBit);    // Hilite using Hilite Color
  1194.                 LineTo(r.left,r.bottom);
  1195.                 if (dWin->endSel < dWin->editOffset+dWin->linesPerPage*16) {
  1196.                     if (gColorQDFlag)
  1197.                 HiliteMode &= ~(1 << hiliteBit);    // Hilite using Hilite Color
  1198.                     LineTo(r.right,r.bottom);
  1199.                 }
  1200.                 else
  1201.                     MoveTo(r.right,r.bottom);
  1202.                 if (gColorQDFlag)
  1203.                 HiliteMode &= ~(1 << hiliteBit);    // Hilite using Hilite Color
  1204.                 LineTo(r.right,r.top);
  1205.                 if (gColorQDFlag)
  1206.                 HiliteMode &= ~(1 << hiliteBit);    // Hilite using Hilite Color
  1207.                 LineTo(AddrPos+CharPos(HexStart)+HexPos(16)-3,r.top);
  1208.     
  1209.                 r.left = AddrPos+CharPos(AsciiStart)-1;
  1210.                 r.right = AddrPos+CharPos(AsciiStart)+CharPos(endX)+CharWidth-1;
  1211.                 if (gColorQDFlag)
  1212.                 HiliteMode &= ~(1 << hiliteBit);    // Hilite using Hilite Color
  1213.                 InvertRect(&r);
  1214.             }
  1215.             else {
  1216.                 r.top = HeaderHeight+TopMargin+LineNbr(start)*LineHeight;
  1217.                 r.bottom = r.top+LineHeight;
  1218.                 r.left = AddrPos+CharPos(HexStart)+HexPos(startX)-3;
  1219.                 r.right = AddrPos+CharPos(HexStart)+HexPos(endX)+HexWidth-3;
  1220.                 MoveTo(r.left,r.top);
  1221.                 if (gColorQDFlag)
  1222.                 HiliteMode &= ~(1 << hiliteBit);    // Hilite using Hilite Color
  1223.                 LineTo(r.left,r.bottom);
  1224.                 if (dWin->endSel < dWin->editOffset+dWin->linesPerPage*16) {
  1225.                     if (gColorQDFlag)
  1226.                 HiliteMode &= ~(1 << hiliteBit);    // Hilite using Hilite Color
  1227.                     LineTo(r.right,r.bottom);
  1228.                 }
  1229.                 else
  1230.                     MoveTo(r.right,r.bottom);
  1231.                 if (gColorQDFlag)
  1232.                 HiliteMode &= ~(1 << hiliteBit);    // Hilite using Hilite Color
  1233.                 LineTo(r.right,r.top);
  1234.                 if (dWin->startSel >= dWin->editOffset) {
  1235.                     if (gColorQDFlag)
  1236.                 HiliteMode &= ~(1 << hiliteBit);    // Hilite using Hilite Color
  1237.                     LineTo(r.left,r.top);
  1238.                 }
  1239.     
  1240.                 r.left = AddrPos+CharPos(AsciiStart)+CharPos(startX)-1;
  1241.                 r.right = AddrPos+CharPos(AsciiStart)+CharPos(endX)+CharWidth-1;
  1242.                 if (gColorQDFlag)
  1243.                 HiliteMode &= ~(1 << hiliteBit);    // Hilite using Hilite Color
  1244.                 InvertRect(&r);
  1245.             }
  1246.         }
  1247.     }
  1248.     PenMode(patCopy);
  1249. }
  1250.  
  1251. void PrintWindow(EditWindowPtr dWin)
  1252. {
  1253.     TPPrPort    printPort;
  1254.     TPrStatus    prStatus;
  1255.     GrafPtr        savePort;
  1256.     Boolean        ok;
  1257.     Rect        r;
  1258.     short        pageNbr,startPage,endPage,nbrPages;
  1259.     long        startAddr,endAddr,addr;
  1260.     short        linesPerPage;
  1261.  
  1262.     GetPort(&savePort);
  1263.     PrOpen();
  1264.  
  1265.     ok = PrValidate(gHPrint);
  1266.     ok = PrJobDialog(gHPrint);
  1267.     if (ok) {
  1268.         if (dWin->startSel == dWin->endSel) {
  1269.             startAddr = 0;
  1270.             endAddr = dWin->fileSize;
  1271.         }
  1272.         else {
  1273.             startAddr = dWin->startSel;
  1274.             endAddr = dWin->endSel;
  1275.         }
  1276.  
  1277.         printPort = PrOpenDoc(gHPrint,NULL,NULL);
  1278.  
  1279.         r = printPort->gPort.portRect;
  1280.         linesPerPage = ((r.bottom - FooterHeight) - TopMargin - BotMargin - HeaderHeight)/LineHeight;
  1281.         nbrPages = ((endAddr - startAddr)/16)/linesPerPage + 1;
  1282.  
  1283.         startPage = (**gHPrint).prJob.iFstPage;
  1284.         endPage = (**gHPrint).prJob.iLstPage;
  1285.         if (startPage > nbrPages) {
  1286.             PrCloseDoc(printPort);
  1287.             ErrorAlert(ES_Caution, "Selected pages are out of range 1-%d",nbrPages);
  1288.             goto ErrorExit;
  1289.         }
  1290.         addr = startAddr;
  1291.  
  1292.         if (endPage > nbrPages)
  1293.             endPage = nbrPages;
  1294.  
  1295.         for (pageNbr = 1; pageNbr <= nbrPages; ++pageNbr) {
  1296.             SetPort(&printPort->gPort);
  1297.             PrOpenPage(printPort, NULL);
  1298.     
  1299.             if (pageNbr >= startPage && pageNbr <= endPage) {
  1300.                 r = printPort->gPort.portRect;
  1301.                 DrawHeader(dWin, &r);
  1302.         
  1303.                 r.top += (HeaderHeight+TopMargin+LineHeight-DescendHeight);
  1304.                 r.bottom -= (FooterHeight + DescendHeight + BotMargin);
  1305.         
  1306.                 DrawDump(dWin, &r, addr, endAddr);
  1307.     
  1308.                 r.top = r.bottom + DescendHeight + BotMargin;
  1309.                 r.bottom = r.top + FooterHeight;
  1310.                 DrawFooter(dWin, &r, pageNbr, nbrPages);
  1311.             }
  1312.  
  1313.             addr += linesPerPage*16;
  1314.             addr -= (addr % 16);
  1315.             PrClosePage(printPort);
  1316.         }
  1317.         PrCloseDoc(printPort);
  1318.         if ((**gHPrint).prJob.bJDocLoop == bSpoolLoop && PrError() == noErr)
  1319.             PrPicFile(gHPrint, NULL, NULL, NULL, &prStatus);
  1320.     }
  1321. ErrorExit:
  1322.     PrClose();
  1323.     SetPort(savePort);
  1324. }
  1325.  
  1326. void ScrollToSelection(EditWindowPtr dWin, long pos, Boolean forceUpdate, Boolean centerFlag)
  1327. {
  1328.     long    curAddr,newAddr;
  1329.     curAddr = dWin->editOffset;
  1330.     if (pos >= curAddr && pos < curAddr+(dWin->linesPerPage<<4)) {
  1331.         if (forceUpdate) {
  1332.             DrawPage(dWin);
  1333.             UpdateOnscreen((WindowPtr) dWin);
  1334.         }
  1335.         AdjustScrollBars((WindowPtr) dWin,false);
  1336.         return;
  1337.     }
  1338.     if (centerFlag) {
  1339.         curAddr = pos - (pos % 16);
  1340.         curAddr -= 16 * (dWin->linesPerPage/2 - 1);
  1341.         // No need to adjust for limits, will be done by scroll routine
  1342.     }
  1343.     else {
  1344.  
  1345.         if (pos < curAddr) {
  1346.             // Scroll Up
  1347.             curAddr = pos;
  1348.             curAddr -= (curAddr % 16);
  1349.         }
  1350.         else {
  1351.             // Scroll Down
  1352.             curAddr = pos - (dWin->linesPerPage-1)*16;
  1353.             curAddr -= (curAddr % 16);
  1354.         }
  1355.     }
  1356.     HEditScrollToPosition(dWin, curAddr);
  1357. }
  1358.  
  1359. void OffsetSelection(EditWindowPtr dWin, short offset, Boolean shiftFlag)
  1360. {
  1361.     long    selWidth;
  1362.     Boolean    fullUpdate;
  1363.     selWidth = dWin->endSel - dWin->startSel;
  1364.     fullUpdate = shiftFlag || selWidth > 1;
  1365.     if (offset < 0) {
  1366.         if (dWin->startSel > 0) {
  1367.             dWin->startSel += offset;
  1368.             if (dWin->startSel < 0)
  1369.                 dWin->startSel = 0;
  1370.             if (!shiftFlag) {
  1371.                 dWin->endSel = dWin->startSel;
  1372.                 CursorOff((WindowPtr) dWin);
  1373.             }
  1374.             ScrollToSelection(dWin, dWin->startSel, fullUpdate, false);
  1375.             if (!shiftFlag)
  1376.                 CursorOn((WindowPtr) dWin);
  1377.         }
  1378.         else
  1379.             SysBeep(1);
  1380.     }
  1381.     else {
  1382.         if (dWin->endSel < dWin->fileSize) {
  1383.             dWin->endSel += offset;
  1384.             if (dWin->endSel > dWin->fileSize)
  1385.                 dWin->endSel = dWin->fileSize;
  1386.             if (!shiftFlag) {
  1387.                 dWin->startSel = dWin->endSel;
  1388.                 CursorOff((WindowPtr) dWin);
  1389.             }
  1390.             ScrollToSelection(dWin, dWin->endSel, fullUpdate, false);
  1391.             if (!shiftFlag)
  1392.                 CursorOn((WindowPtr) dWin);
  1393.         }
  1394.         else
  1395.             SysBeep(1);
  1396.     }
  1397. }
  1398.  
  1399. void MyProcessKey(WindowPtr theWin, EventRecord *er)
  1400. {
  1401.     short    charCode,keyCode;
  1402.     EditWindowPtr    dWin = (EditWindowPtr) theWin;
  1403.  
  1404.     keyCode = (er->message & keyCodeMask) >> 8;
  1405.     charCode = (er->message & charCodeMask);
  1406.  
  1407.     if (er->modifiers & cmdKey)
  1408.         return;
  1409.  
  1410.     switch (keyCode) {
  1411.     case  0x24:            // Return
  1412.         break;
  1413.     case  0x7B:            // Left
  1414.         OffsetSelection(dWin, -1, (er->modifiers & shiftKey)>0);
  1415.         break;
  1416.     case 0x7C:            // Right
  1417.         OffsetSelection(dWin, 1, (er->modifiers & shiftKey)>0);
  1418.         break;
  1419.     case 0x7E:            // Up
  1420.         OffsetSelection(dWin, -16, (er->modifiers & shiftKey)>0);
  1421.         break;
  1422.     case 0x7D:            // Down
  1423.         OffsetSelection(dWin, 16, (er->modifiers & shiftKey)>0);
  1424.         break;
  1425.     case 0x33:            // Delete
  1426.         if (dWin->endSel > dWin->startSel) {
  1427.             ClearSelection(dWin);
  1428.         }
  1429.         else if (dWin->startSel > 0L) {
  1430.             ObscureCursor();
  1431.             --dWin->startSel;
  1432.             ClearSelection(dWin);
  1433.         }
  1434.         else
  1435.             SysBeep(1);
  1436.         break;
  1437.     default:
  1438.         // Insert Ascii Text Into Area indicated by dWin->startSel - dWin->endSel
  1439.         // Delete Current Selection if > 0
  1440.         ObscureCursor();
  1441.  
  1442.         if (dWin->editMode == EM_Ascii) {
  1443.             if (dWin->endSel != dWin->lastTypePos ||
  1444.                 dWin->startSel != dWin->lastTypePos)
  1445.                 RememberOperation(dWin, EO_Typing, &gUndoRec);
  1446.             if (dWin->endSel > dWin->startSel)
  1447.                 DeleteSelection(dWin);
  1448.             if (gOverwrite && dWin->startSel < dWin->fileSize - 1) {
  1449.                 ++dWin->endSel;
  1450.                 DeleteSelection(dWin);
  1451.             }
  1452.             InsertCharacter(dWin, charCode);
  1453.             dWin->lastTypePos = dWin->startSel;
  1454.         }
  1455.         else {
  1456.             short    hexVal;
  1457.  
  1458.             if (charCode >= '0' && charCode <= '9')
  1459.                 hexVal = charCode - '0';
  1460.             else if (charCode >= 'A' && charCode <= 'F')
  1461.                 hexVal = 0x0A + charCode - 'A';
  1462.             else if (charCode >= 'a' && charCode <= 'f')
  1463.                 hexVal = 0x0A + charCode - 'a';
  1464.             else {
  1465.                 SysBeep(1);
  1466.                 return;
  1467.             }
  1468.  
  1469.             if (dWin->endSel != dWin->lastTypePos ||
  1470.                 dWin->startSel != dWin->lastTypePos) {
  1471.                 dWin->loByteFlag = false;
  1472.                 RememberOperation(dWin, EO_Typing, &gUndoRec);
  1473.             }
  1474.             if (dWin->endSel > dWin->startSel)
  1475.                 DeleteSelection(dWin);
  1476.  
  1477.             if (dWin->loByteFlag) {
  1478.                 --dWin->startSel;
  1479.                 DeleteSelection(dWin);
  1480.                 hexVal = hexVal | (dWin->lastNybble << 4);
  1481.                 InsertCharacter(dWin, hexVal);
  1482.                 dWin->loByteFlag = false;
  1483.             }
  1484.             else {
  1485.                 if (gOverwrite && dWin->startSel < dWin->fileSize - 1) {
  1486.                     ++dWin->endSel;
  1487.                     DeleteSelection(dWin);
  1488.                 }
  1489.                 InsertCharacter(dWin, hexVal);
  1490.                 dWin->lastNybble = hexVal;
  1491.                 dWin->loByteFlag = true;
  1492.             }
  1493.             dWin->lastTypePos = dWin->startSel;
  1494.         }
  1495.         break;
  1496.     }
  1497. }
  1498.  
  1499. void CursorOff(WindowPtr theWin)
  1500. {
  1501.     if (gCursorFlag) {
  1502.         gCursorFlag = false;
  1503.         SetPort(theWin);
  1504.         InvertRect(&gCursRect);
  1505.     }
  1506. }
  1507.  
  1508. void CursorOn(WindowPtr theWin)
  1509. {
  1510.     EditWindowPtr    dWin = (EditWindowPtr) theWin;
  1511.     long            start;
  1512.     Rect            r;
  1513.  
  1514.     if (!gCursorFlag &&
  1515.          dWin->startSel >= dWin->editOffset &&
  1516.         dWin->startSel < dWin->editOffset+(dWin->linesPerPage<<4)) 
  1517.     {
  1518.         gCursorFlag = true;
  1519.         SetPort(theWin);
  1520.         start = dWin->startSel - dWin->editOffset;
  1521.  
  1522.         if (dWin->editMode == EM_Hex) {
  1523.             r.top = HeaderHeight+TopMargin+LineNbr(start)*LineHeight;
  1524.             r.bottom = r.top+LineHeight;
  1525.             r.left = AddrPos+CharPos(HexStart)+ColNbr(start)*HexWidth-3;
  1526.             r.right = r.left+2;
  1527.             InvertRect(&r);
  1528.             gCursRect = r;
  1529.         }
  1530.         else {
  1531.             r.top = HeaderHeight+TopMargin+LineNbr(start)*LineHeight;
  1532.             r.bottom = r.top+LineHeight;
  1533.             r.left = AddrPos+CharPos(AsciiStart)+ColNbr(start)*CharWidth-2;
  1534.             r.right = r.left+2;
  1535.             InvertRect(&r);
  1536.             gCursRect = r;
  1537.         }
  1538.     }
  1539. }
  1540.  
  1541. OSErr CopyFork(FSSpec *srcSpec, FSSpec *dstSpec, short forkType)
  1542. {
  1543.     short    sRefNum, dRefNum;
  1544.     OSErr    oe;
  1545.     Ptr        tBuffer;
  1546.     long    srcSize=0L,bufSize,count;
  1547.  
  1548.     tBuffer = NewPtr(32000);
  1549.  
  1550.     if (tBuffer == NULL) {
  1551.         ErrorAlert(ES_Caution, "Not Enough Memory");
  1552.         return 1;
  1553.     }
  1554.     if (forkType == FT_Resource) {
  1555.         oe = HOpenRF(srcSpec->vRefNum,srcSpec->parID,srcSpec->name,fsRdPerm,&sRefNum);
  1556.         if (oe != noErr) {
  1557.             OSErrorAlert(ES_Caution, "HOpenRF", oe);
  1558.             return oe;
  1559.         }
  1560.         oe = HOpenRF(dstSpec->vRefNum,dstSpec->parID,dstSpec->name,fsWrPerm,&dRefNum);
  1561.         if (oe != noErr) {
  1562.             OSErrorAlert(ES_Caution, "HOpenRF", oe);
  1563.             return oe;
  1564.         }
  1565.     }
  1566.     else {
  1567.         oe = HOpen(srcSpec->vRefNum,srcSpec->parID,srcSpec->name,fsRdPerm,&sRefNum);
  1568.         if (oe != noErr) {
  1569.             OSErrorAlert(ES_Caution, "HOpen", oe);
  1570.             return oe;
  1571.         }
  1572.         oe = HOpen(dstSpec->vRefNum,dstSpec->parID,dstSpec->name,fsWrPerm,&dRefNum);
  1573.         if (oe != noErr) {
  1574.             OSErrorAlert(ES_Caution, "HOpen", oe);
  1575.             return oe;
  1576.         }
  1577.     }
  1578.     GetEOF(sRefNum, &srcSize);
  1579.     SetEOF(dRefNum,0L);
  1580.     while (srcSize) {
  1581.         if (srcSize < 32000)
  1582.             bufSize = srcSize;
  1583.         else
  1584.             bufSize = 32000;
  1585.         srcSize -= bufSize;
  1586.         count = bufSize;
  1587.         oe = FSRead(sRefNum, &count, tBuffer);
  1588.         if (oe != noErr) {
  1589.             OSErrorAlert(ES_Caution,"FSRead",oe);
  1590.             goto ErrorExit;
  1591.         }
  1592.         oe = FSWrite(dRefNum, &count, tBuffer);
  1593.         if (oe != noErr) {
  1594.             OSErrorAlert(ES_Caution,"FSWrite",oe);
  1595.             goto ErrorExit;
  1596.         }
  1597.     }
  1598.     oe = noErr;
  1599. ErrorExit:
  1600.     FSClose(sRefNum);
  1601.     FSClose(dRefNum);
  1602.     DisposePtr(tBuffer);
  1603.     return oe;
  1604. }
  1605.  
  1606. void InsureNameIsUnique(FSSpec *tSpec)
  1607. {
  1608.     FInfo            fInfo;
  1609.     while (HGetFInfo(tSpec->vRefNum,
  1610.                      tSpec->parID,
  1611.                      tSpec->name, &fInfo) == noErr) {
  1612.         tSpec->name[1+MyRandom(tSpec->name[0])] = 0x80+MyRandom(64);
  1613.     }
  1614. }
  1615.  
  1616. void SaveContents(WindowPtr theWin)
  1617. {
  1618.     short            tRefNum=0;
  1619.     FSSpec            tSpec,bSpec;
  1620.     HParamBlockRec    pb;
  1621.     EditChunk        **cc;
  1622.     EditWindowPtr    dWin;
  1623.     long            count;
  1624.     OSErr            oe;
  1625.  
  1626.     dWin = (EditWindowPtr) theWin;
  1627.     if (dWin->destSpec.name[0] == 0) {
  1628.         SaveAsContents(theWin);
  1629.     }
  1630.     else {
  1631.         // Create temp file
  1632.         tSpec = dWin->destSpec;
  1633.  
  1634.         // If original file exists, write to temp folder
  1635.         if (dWin->refNum) {
  1636.             if (tSpec.name[0] < 31) {
  1637.                 tSpec.name[0]++;
  1638.                 tSpec.name[tSpec.name[0]] = 't';
  1639.             }
  1640.             else {
  1641.                 tSpec.name[31] ^= 0x10;
  1642.             }
  1643.         }
  1644.         InsureNameIsUnique(&tSpec);
  1645.  
  1646.         HDelete(tSpec.vRefNum,tSpec.parID,tSpec.name);
  1647.         oe = HCreate(tSpec.vRefNum,tSpec.parID,tSpec.name,dWin->creator, dWin->fileType);
  1648.         if (oe != noErr) {
  1649.             OSErrorAlert(ES_Caution, "HCreate", oe);
  1650.             return;
  1651.         }
  1652.  
  1653.         // Preserve creation date of orig file if it exists
  1654.         if (dWin->creationDate) {
  1655.             pb.fileParam.ioCompletion = 0l;
  1656.             pb.fileParam.ioNamePtr = tSpec.name;
  1657.             pb.fileParam.ioVRefNum = tSpec.vRefNum;
  1658.             pb.fileParam.ioDirID = tSpec.parID;
  1659.             pb.fileParam.ioFDirIndex = 0;
  1660.         
  1661.             if ((oe = PBHGetFInfo(&pb,FALSE)) != noErr) {
  1662.                 OSErrorAlert(ES_Caution, "PBHGetFInfo", oe);
  1663.                 return;
  1664.             }
  1665.             // Reset dirID which PBHGeFInfo changes...
  1666.             pb.fileParam.ioFlCrDat = dWin->creationDate;
  1667.             pb.fileParam.ioDirID = tSpec.parID;
  1668.             if ((oe = PBHSetFInfo(&pb,FALSE)) != noErr) {
  1669.                 OSErrorAlert(ES_Caution, "PBHSetFInfo", oe);
  1670.                 return;
  1671.             }
  1672.         }
  1673.         // Preserve other fork if it exists
  1674.         if (dWin->refNum)
  1675.             if (CopyFork(&dWin->fsSpec,&tSpec, !dWin->fork) != noErr)
  1676.                 return;
  1677.  
  1678.         // Open the temp file
  1679.         if (dWin->fork == FT_Resource) {
  1680.             oe = HOpenRF(tSpec.vRefNum,tSpec.parID,tSpec.name,fsWrPerm,&tRefNum);
  1681.             if (oe != noErr) {
  1682.                 OSErrorAlert(ES_Caution, "HOpenRF", oe);
  1683.                 return;
  1684.             }
  1685.         }
  1686.         else {
  1687.             oe = HOpen(tSpec.vRefNum,tSpec.parID,tSpec.name,fsWrPerm,&tRefNum);
  1688.             if (oe != noErr) {
  1689.                 OSErrorAlert(ES_Caution, "HOpen", oe);
  1690.                 return;
  1691.             }
  1692.         }
  1693.         
  1694.         // Save out to temp file
  1695.         cc = dWin->firstChunk;
  1696.         while (cc) {
  1697.             LoadChunk(dWin, cc);
  1698.             count = (*cc)->size;
  1699.             oe = FSWrite(tRefNum, &count, *(*cc)->data);
  1700.             if (oe != noErr) {
  1701.                 // !! Error Message - write error
  1702.                 FSClose(tRefNum);
  1703.                 if (oe == dskFulErr)
  1704.                     goto DiskFull;
  1705.                 OSErrorAlert(ES_Caution, "FSWrite", oe);
  1706.                 return;
  1707.             }
  1708.             cc = (*cc)->next;
  1709.         }
  1710.  
  1711.         // Close temp file
  1712.         FSClose(tRefNum);
  1713.  
  1714.         // If Original File Exists
  1715.         if (dWin->refNum) {
  1716.             // Close original file
  1717.             FSClose(dWin->refNum);
  1718.  
  1719.             bSpec = dWin->destSpec;
  1720.  
  1721.             // If it exists under current name
  1722.             if ((oe = HOpen(bSpec.vRefNum,bSpec.parID,bSpec.name,fsRdPerm,&dWin->refNum)) == noErr)
  1723.             {
  1724.                 FSClose(dWin->refNum);
  1725.  
  1726.                 if (gPrefs.backupFlag) {
  1727.                     // Delete last backup file, if it exists
  1728.                     bSpec = dWin->destSpec;
  1729.                     bSpec.name[0]++;
  1730.                     bSpec.name[bSpec.name[0]] = '~';
  1731.                     HDelete(bSpec.vRefNum,bSpec.parID,bSpec.name);
  1732.         
  1733.                     // Rename original file to backup name
  1734.                     oe = HRename(dWin->destSpec.vRefNum,
  1735.                                  dWin->destSpec.parID,
  1736.                                  dWin->destSpec.name,
  1737.                                   bSpec.name);
  1738.                     if (oe != noErr) {
  1739.                         // Backup is probably open, just delete original
  1740.                         ErrorAlert(ES_Caution, "Can't backup original - backup file is open", oe);
  1741.                         bSpec = dWin->destSpec;
  1742.                         HDelete(bSpec.vRefNum,bSpec.parID,bSpec.name);
  1743.                     }
  1744.                 }
  1745.                 else {
  1746.                     // Delete Original if backup flag is false
  1747.                     bSpec = dWin->destSpec;
  1748.                     HDelete(bSpec.vRefNum,bSpec.parID,bSpec.name);
  1749.                 }
  1750.             }
  1751.  
  1752.             // Rename temp file to correct name
  1753.             oe = HRename(tSpec.vRefNum,
  1754.                         tSpec.parID,
  1755.                         tSpec.name,
  1756.                         dWin->destSpec.name);
  1757.             if (oe != noErr) {
  1758.                 OSErrorAlert(ES_Stop, "HRename", oe);
  1759.             }
  1760.         }
  1761.  
  1762.         // Open newly saved file read only
  1763.         tSpec = dWin->destSpec;
  1764.         if (dWin->fork == FT_Resource) {
  1765.             oe = HOpenRF(tSpec.vRefNum,tSpec.parID,tSpec.name,fsRdPerm,&dWin->refNum);
  1766.             if (oe != noErr) {
  1767.                 OSErrorAlert(ES_Stop, "HOpenRF", oe);
  1768.             }
  1769.         }
  1770.         else {
  1771.             oe = HOpen(tSpec.vRefNum,tSpec.parID,tSpec.name,fsRdPerm,&dWin->refNum);
  1772.             if (oe != noErr) {
  1773.                 OSErrorAlert(ES_Stop, "HOpen", oe);
  1774.             }
  1775.         }
  1776.  
  1777.         // Reset Work File
  1778.         dWin->fsSpec = dWin->destSpec;
  1779.         SetWTitle((WindowPtr) dWin, dWin->fsSpec.name);
  1780.  
  1781.         dWin->workBytesWritten = 0L;
  1782.         SetEOF(dWin->workRefNum, 0L);
  1783.  
  1784.         // Flush the volume
  1785.         pb.volumeParam.ioCompletion = NULL;
  1786.         pb.volumeParam.ioNamePtr = NULL;
  1787.         pb.volumeParam.ioVRefNum = tSpec.vRefNum;
  1788.         PBFlushVol((ParmBlkPtr) &pb, FALSE);
  1789.  
  1790.         // Clear linked list
  1791.         UnloadFile(dWin);
  1792.  
  1793.         // Rebuilt linked list
  1794.         LoadFile(dWin);
  1795.  
  1796.         // Clear Dirty Flag
  1797.         dWin->dirtyFlag = false;
  1798.     }
  1799.     return;
  1800. DiskFull:
  1801.     ErrorAlert(ES_Caution, "Can't save - the disk is full.  Try freeing some space or using another disk.");
  1802.     HDelete(tSpec.vRefNum,tSpec.parID,tSpec.name);
  1803. }
  1804.  
  1805. void SaveAsContents(WindowPtr theWin)
  1806. {
  1807.     StandardFileReply    reply;
  1808.     EditWindowPtr        dWin = (EditWindowPtr) theWin;
  1809.     Str63                fileName;
  1810.     GetWTitle(theWin, fileName);
  1811.     StandardPutFile("\pFile to save:", 
  1812.                     fileName, 
  1813.                     &reply);
  1814.     if (reply.sfGood) {
  1815.         dWin->destSpec = reply.sfFile;
  1816.         dWin->creationDate = 0;
  1817.         SaveContents(theWin);
  1818.     }
  1819. }
  1820.  
  1821. void RevertContents(WindowPtr theWin)
  1822. {
  1823.     EditWindowPtr    dWin = (EditWindowPtr) theWin;
  1824.     long            newEOF;
  1825.  
  1826.     // Reset Work File
  1827.     dWin->workBytesWritten = 0L;
  1828.     SetEOF(dWin->workRefNum, 0L);
  1829.  
  1830.     // Clear linked list
  1831.     UnloadFile(dWin);
  1832.  
  1833.     // Reset EOF
  1834.     GetEOF(dWin->refNum, &newEOF);
  1835.  
  1836.     dWin->fileSize = newEOF;
  1837.  
  1838.     // Rebuilt linked list
  1839.     LoadFile(dWin);
  1840.  
  1841.     // Reset scroll offset, if necessary
  1842.     if (dWin->editOffset > dWin->fileSize -16*dWin->linesPerPage)
  1843.         dWin->editOffset = 0;
  1844.     DrawPage(dWin);
  1845.     UpdateOnscreen(theWin);
  1846. }
  1847.  
  1848. void MyActivate(WindowPtr theWin, Boolean active)
  1849. {
  1850.     EditWindowPtr    dWin = (EditWindowPtr) theWin;
  1851.     if (dWin->vScrollBar)
  1852.         HiliteControl(dWin->vScrollBar,active? 0 : 255);
  1853.     DefaultActivate(theWin, active);
  1854. }
  1855.  
  1856. void UpdateEditWindows()
  1857. {
  1858.     WindowPeek    theWin;
  1859.     theWin = (WindowPeek) FrontWindow();
  1860.     while (theWin) {
  1861.         if (theWin->refCon == MyWindowID) {
  1862.             DrawPage((EditWindowPtr) theWin);
  1863.             UpdateOnscreen((WindowPtr) theWin);
  1864.         }
  1865.         theWin = theWin->nextWindow;
  1866.     }
  1867. }
  1868.  
  1869.